﻿// RankingSejmowy 1.0 - Polish parliment statistics for the masses.
// Copyright (C) 2010 Jarosław Dubrownik
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
using System.Data;
using System.Diagnostics;
using System.Linq;
using NHibernate;
using RankingSejmowy.BLL.Import.Mappers;
using RankingSejmowy.Common.Localization;
using RankingSejmowy.Common.Logging;
using RankingSejmowy.DAL.Cadences;
using RankingSejmowy.DAL.Deputies;
using RankingSejmowy.DAL.Parties;
using RankingSejmowy.Model;

namespace RankingSejmowy.BLL.Import
{
    public class ImportService : IImportService
    {
        private readonly ICadenceRepository _cadenceRepository;
        private readonly IDeputyRepository _deputyRepository;
        private readonly IDiffMapper _diffMapper;
        private readonly IParliment _parliment;
        private readonly IPartyRepository _partyRepository;
        private readonly IProgressLog _progressLog;
        private readonly ISession _session;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="parliment">ParlimentDataProvider object used to fetch parliment parliment.</param>
        /// <param name="cadenceRepository">Cadence repository.</param>
        /// <param name="partyRepository"></param>
        /// <param name="diffMapper">Mapper for differental mapping from one cadence to another.</param>
        /// <param name="complexCalculation">Calculating complex statistics after import data.</param>
        /// <param name="entityRebuilder"></param>
        /// <param name="progressLog">Logger.</param>
        /// <param name="deputyRepository"></param>
        /// <param name="session"></param>
        public ImportService(IParliment parliment, ICadenceRepository cadenceRepository,
                             IDeputyRepository deputyRepository, IPartyRepository partyRepository,
                             IDiffMapper diffMapper, IProgressLog progressLog, ISession session)
        {
            _parliment = parliment;
            _cadenceRepository = cadenceRepository;
            _deputyRepository = deputyRepository;
            _partyRepository = partyRepository;
            _diffMapper = diffMapper;
            _progressLog = progressLog;
            _session = session;
        }

        ///// <summary>
        ///// Imports parliment cadence parliment into database.
        ///// </summary>
        ///// <param name="cadenceNum">Cadence number.</param>
        //public void ImportCadence(int cadenceNum)
        //{
        //    Debug.Assert(cadenceNum > 0);

        //    using (var scope = new TransactionScope())
        //    {
        //        var cadence = _cadenceRepository.GetByCadenceNum(cadenceNum);
        //        var setup = new FetchSetup { Cadence = cadence.CadenceNum, Inceremental = false };
        //        DoTheCadenceImport(cadence, setup);
        //        _progressLog.ReportStatus(string.Format(AppStrings.SavingCadenceVotingFmt, setup.LastMeeting + 1,
        //                                                setup.Cadence));
        //        scope.Complete();
        //    }
        //}

        #region IImportService Members

        public ImportInfo GetLastImportInfo(int cadenceNum)
        {
            Debug.Assert(cadenceNum > 0);

            var meeting = _cadenceRepository.GetCadenceLastMeeting(cadenceNum, _session);
            var meetingNum = meeting != null ? meeting.MeetingNum : 0;
            return new ImportInfo {CadenceNum = cadenceNum, MeetingNum = meetingNum};
        }

        public Meeting[] GetNonFetchedMeetings(int cadenceNum)
        {
            Debug.Assert(cadenceNum > 0);

            var lastMeeting = _cadenceRepository.GetCadenceLastMeeting(cadenceNum, _session);
            var meetings = _parliment.FetchMeetingList(cadenceNum);
            if (lastMeeting == null)
            {
                return meetings;
            }

            return meetings.Where(x => x.MeetingNum > lastMeeting.MeetingNum).ToArray();
        }

        public void ImportCadence(int cadenceNum, int lastMeeting, int meetingsToImport)
        {
            using (var tran = _session.BeginTransaction(IsolationLevel.ReadCommitted))
            {
                var cadence = _cadenceRepository.GetByCadenceNum(cadenceNum, _session);
                var setup = new FetchSetup
                                {
                                    Cadence = cadenceNum,
                                    LastMeeting = lastMeeting,
                                    Inceremental = true,
                                    MeetingsToFetch = meetingsToImport
                                };
                DoTheCadenceImport(cadence, setup);
                tran.Commit();
            }
        }

        #endregion

        private void DoTheCadenceImport(Cadence cadence, FetchSetup setup)
        {
            _progressLog.ReportStatus(string.Format(AppStrings.FetchingCadenceVotingFmt, setup.LastMeeting + 1,
                                                    setup.Cadence));
            var importedCadence = _parliment.FetchCadence(setup);
            if (cadence == null)
            {
                _progressLog.ReportStatus(string.Format(AppStrings.SavingCadenceVotingFmt, setup.LastMeeting + 1,
                                                        setup.Cadence));
                _cadenceRepository.Save(importedCadence, _session);
                return;
            }

            _progressLog.ReportStatus(string.Format(AppStrings.ProcessingCadenceVotingFmt, setup.LastMeeting + 1,
                                                    setup.Cadence));
            _diffMapper.MapCadence(cadence, importedCadence);
            _progressLog.ReportStatus(string.Format(AppStrings.SavingCadenceVotingFmt, setup.LastMeeting + 1,
                                                    setup.Cadence));
            _cadenceRepository.Save(cadence, _session);
        }
    }
}